From 246c9e2a55ade2410609eb3b913898dcc4695f95 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Thu, 10 Jul 2014 15:13:53 -0700 Subject: [PATCH] Add support for examples --- src/cargo/core/manifest.rs | 10 ++++++ src/cargo/util/toml.rs | 66 +++++++++++++++++++++++++++++++++++-- tests/test_cargo_compile.rs | 66 +++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 981547116..6d130aa6f 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -343,6 +343,16 @@ impl Target { } } + pub fn example_target(name: &str, src_path: &Path, profile: &Profile) -> Target { + Target { + kind: BinTarget, + name: name.to_string(), + src_path: src_path.clone(), + profile: profile.clone(), + metadata: None + } + } + pub fn get_name<'a>(&'a self) -> &'a str { self.name.as_slice() } diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 232cf0a0e..b8c62cc07 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -14,7 +14,8 @@ use util::{CargoResult, Require, human}; #[deriving(Clone)] pub struct Layout { lib: Option, - bins: Vec + bins: Vec, + examples: Vec, } impl Layout { @@ -31,6 +32,7 @@ impl Layout { pub fn project_layout(root: &Path) -> Layout { let mut lib = None; let mut bins = vec!(); + let mut examples = vec!(); if root.join("src/lib.rs").exists() { lib = Some(root.join("src/lib.rs")); @@ -46,9 +48,16 @@ pub fn project_layout(root: &Path) -> Layout { .map(|mut i| i.collect()) .map(|found| bins.push_all_move(found)); + let _ = fs::readdir(&root.join("examples")) + .map(|v| v.move_iter()) + .map(|i| i.filter(|f| f.extension_str() == Some("rs"))) + .map(|mut i| i.collect()) + .map(|found| examples.push_all_move(found)); + Layout { lib: lib, - bins: bins + bins: bins, + examples: examples, } } @@ -129,6 +138,7 @@ pub fn parse(toml: &str, file: &str) -> CargoResult { type TomlLibTarget = TomlTarget; type TomlBinTarget = TomlTarget; +type TomlExampleTarget = TomlTarget; /* * TODO: Make all struct fields private @@ -157,6 +167,7 @@ pub struct TomlManifest { project: Option>, lib: Option>, bin: Option>, + example: Option>, dependencies: Option>, dev_dependencies: Option> } @@ -227,6 +238,22 @@ fn inferred_bin_targets(name: &str, layout: &Layout) -> Option> }).collect()) } +fn inferred_example_targets(layout: &Layout) -> Option> { + Some(layout.examples.iter().filter_map(|ex| { + let name = ex.filestem_str().map(|f| f.to_string()); + + name.map(|name| { + TomlTarget { + name: name, + crate_type: None, + path: Some(ex.display().to_string()), + test: None, + plugin: None, + } + }) + }).collect()) +} + impl TomlManifest { pub fn to_manifest(&self, source_id: &SourceId, layout: &Layout) -> CargoResult<(Manifest, Vec)> @@ -284,9 +311,18 @@ impl TomlManifest { }).collect()) }; + let examples = if self.example.is_none() || self.example.get_ref().is_empty() { + inferred_example_targets(layout) + } else { + Some(self.example.get_ref().iter().map(|t| { + t.clone() + }).collect()) + }; + // Get targets let targets = normalize(lib.as_ref().map(|l| l.as_slice()), bins.as_ref().map(|b| b.as_slice()), + examples.as_ref().map(|e| e.as_slice()), &metadata); if targets.is_empty() { @@ -386,10 +422,11 @@ struct TomlTarget { fn normalize(lib: Option<&[TomlLibTarget]>, bin: Option<&[TomlBinTarget]>, + example: Option<&[TomlExampleTarget]>, metadata: &Metadata) -> Vec { - log!(4, "normalizing toml targets; lib={}; bin={}", lib, bin); + log!(4, "normalizing toml targets; lib={}; bin={}; example={}", lib, bin, example); enum TestDep { Needed, NotNeeded } @@ -444,6 +481,20 @@ fn normalize(lib: Option<&[TomlLibTarget]>, } } + fn example_targets(dst: &mut Vec, examples: &[TomlExampleTarget], + default: |&TomlExampleTarget| -> String) { + for ex in examples.iter() { + let path = ex.path.clone().unwrap_or_else(|| default(ex)); + + let profile = &Profile::default_test().test(false); + { + dst.push(Target::example_target(ex.name.as_slice(), + &Path::new(path.as_slice()), + profile)); + } + } + } + let mut ret = Vec::new(); match (lib, bin) { @@ -462,5 +513,14 @@ fn normalize(lib: Option<&[TomlLibTarget]>, (None, None) => () } + + match example { + Some(ref examples) => { + example_targets(&mut ret, examples.as_slice(), + |ex| format!("examples/{}.rs", ex.name)); + }, + None => () + } + ret } diff --git a/tests/test_cargo_compile.rs b/tests/test_cargo_compile.rs index 7c2d0affb..489c77753 100644 --- a/tests/test_cargo_compile.rs +++ b/tests/test_cargo_compile.rs @@ -1072,3 +1072,69 @@ test!(verbose_release_build_deps { hash1 = hash1, hash2 = hash2).as_slice()); }) + +test!(explicit_examples { + let mut p = project("world"); + p = p.file("Cargo.toml", r#" + [package] + name = "world" + version = "1.0.0" + authors = [] + + [[lib]] + name = "world" + path = "src/lib.rs" + + [[example]] + name = "hello" + path = "examples/ex-hello.rs" + + [[example]] + name = "goodbye" + path = "examples/ex-goodbye.rs" + "#) + .file("src/lib.rs", r#" + pub fn get_hello() -> &'static str { "Hello" } + pub fn get_goodbye() -> &'static str { "Goodbye" } + pub fn get_world() -> &'static str { "World" } + "#) + .file("examples/ex-hello.rs", r#" + extern crate world; + fn main() { println!("{}, {}!", world::get_hello(), world::get_world()); } + "#) + .file("examples/ex-goodbye.rs", r#" + extern crate world; + fn main() { println!("{}, {}!", world::get_goodbye(), world::get_world()); } + "#); + + assert_that(p.cargo_process("cargo-test"), execs()); + assert_that(process(p.bin("test/hello")), execs().with_stdout("Hello, World!\n")); + assert_that(process(p.bin("test/goodbye")), execs().with_stdout("Goodbye, World!\n")); +}) + +test!(implicit_examples { + let mut p = project("world"); + p = p.file("Cargo.toml", r#" + [package] + name = "world" + version = "1.0.0" + authors = [] + "#) + .file("src/lib.rs", r#" + pub fn get_hello() -> &'static str { "Hello" } + pub fn get_goodbye() -> &'static str { "Goodbye" } + pub fn get_world() -> &'static str { "World" } + "#) + .file("examples/hello.rs", r#" + extern crate world; + fn main() { println!("{}, {}!", world::get_hello(), world::get_world()); } + "#) + .file("examples/goodbye.rs", r#" + extern crate world; + fn main() { println!("{}, {}!", world::get_goodbye(), world::get_world()); } + "#); + + assert_that(p.cargo_process("cargo-test"), execs()); + assert_that(process(p.bin("test/hello")), execs().with_stdout("Hello, World!\n")); + assert_that(process(p.bin("test/goodbye")), execs().with_stdout("Goodbye, World!\n")); +}) -- 2.30.2